#include "arbiter_store.h"

NodeArbiterStore::NodeArbiterStore(Node *parent, NodeArbiterStoreParam params) :
    Node(parent)
{
    List<ChannelStoreFabricReceiver *> tmp_885115760;
    for(int temp_885054040=0; temp_885054040<params.num_of_receivers; temp_885054040+=1)
    {
        tmp_885115760.append(new ChannelStoreFabricReceiver(this));
    }
    port_receivers = tmp_885115760;
    List<LaneChannelStoreFabricBusReceiver *> tmp_885066944;
    for(int ii=0; ii<params.num_of_receivers; ii+=1)
    {
        tmp_885066944.append(port_receivers[ii]->Bus);
    }
    port_receiver_lanes = tmp_885066944;
    port_sender = new ChannelStoreFabricSender(this);
    port_sender_lane = port_sender->Bus;
    reg_grant_id = 0;
    NodeAndGateParam node_param_893523056;
    node_param_893523056.num_of_ports = params.num_of_receivers;
    node_halt_detect = new NodeAndGate(this, node_param_893523056);
    List<PortOut<bool> *> tmp_893523952;
    for(int temp_884916120=0; temp_884916120<params.num_of_receivers; temp_884916120+=1)
    {
        tmp_893523952.append(new PortOut<bool>(this));
    }
    port_halt_ins = tmp_893523952;
    for(int ii=0; ii<params.num_of_receivers; ii+=1)
    {
        port_halt_ins[ii]->connect(node_halt_detect->port_and_ins[ii]);
    }
    port_halt = node_halt_detect->port_and_out;
}

NodeTaskList NodeArbiterStore::tasks() const
{
    NodeTaskList list;
    list.append(static_cast<NodeTask>(&NodeArbiterStore::task_halt_detection));
    list.append(static_cast<NodeTask>(&NodeArbiterStore::task_check_and_rotate));
    return list;
}

void NodeArbiterStore::task_halt_detection()
{
    for(int ii=0; ii<port_receivers.size(); ii+=1)
    {
        port_halt_ins[ii]->put(port_receiver_lanes[ii]->is_any_empty());
    }
}

void NodeArbiterStore::task_check_and_rotate()
{
    List<bool> tmp_893524848;
    for(int temp_885070592=0; temp_885070592<port_receivers.size(); temp_885070592+=1)
    {
        tmp_893524848.append(false);
    }
    reg_requests = tmp_893524848;
    reg_request_not_empty = false;
    for(int ii=0; ii<port_receivers.size(); ii+=1)
    {
        reg_requests[ii] = !(port_receiver_lanes[ii]->is_any_empty());
        reg_request_not_empty = (reg_request_not_empty)||(reg_requests[ii]);
    }
    if((!(reg_request_not_empty))||(port_sender_lane->is_any_full()))
    {
        return;
    }
    reg_requests += reg_requests;
    reg_grant_id_org = -1;
    for(int ii=0; ii<reg_requests.size(); ii+=1)
    {
        if(reg_requests[ii])
        {
            reg_grant_id_org = ii;
            break;
        }
    }
    List<bool> tmp_893620576;
    for(int temp_884977448=0; temp_884977448<(reg_grant_id)+(1); temp_884977448+=1)
    {
        tmp_893620576.append(false);
    }
    reg_mask_f = tmp_893620576;
    List<bool> tmp_893621304;
    for(int temp_885093040=0; temp_885093040<((reg_requests.size())-(reg_grant_id))-(1); temp_885093040+=1)
    {
        tmp_893621304.append(true);
    }
    reg_mask_t = tmp_893621304;
    reg_mask = (reg_mask_f)+(reg_mask_t);
    List<bool> tmp_893621920;
    for(int temp_885095056=0; temp_885095056<reg_mask.size(); temp_885095056+=1)
    {
        bool x = reg_mask[temp_885095056];
        bool y = reg_requests[temp_885095056];
        tmp_893621920.append((x)&&(y));
    }
    reg_masked_request = tmp_893621920;
    reg_grant_id_masked = -1;
    for(int ii=0; ii<reg_masked_request.size(); ii+=1)
    {
        if(reg_masked_request[ii])
        {
            reg_grant_id_masked = ii;
            break;
        }
    }
    reg_grant_id = ((reg_grant_id_masked)==(reg_grant_id_org)) ? (reg_grant_id_org) : (reg_grant_id_masked);
    reg_grant_id %= port_receivers.size();
    port_sender_lane->put_bypass(port_receiver_lanes[reg_grant_id]);
}